package org.lucava.boatskeeper.client.view;

import java.util.ArrayList;
import java.util.List;


import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.maps.gwt.client.Animation;
import com.google.maps.gwt.client.GoogleMap;
import com.google.maps.gwt.client.InfoWindow;
import com.google.maps.gwt.client.InfoWindowOptions;
import com.google.maps.gwt.client.LatLng;
import com.google.maps.gwt.client.MapOptions;
import com.google.maps.gwt.client.MapTypeId;
import com.google.maps.gwt.client.Marker;
import com.google.maps.gwt.client.Marker.ClickHandler;
import com.google.maps.gwt.client.MarkerOptions;
import com.google.maps.gwt.client.MouseEvent;
import gwtupload.client.PreloadedImage;
import java.util.HashMap;
import java.util.Map;
import org.lucava.boatskeeper.shared.dto.BoatDto;

public class MapWidget extends Composite {

    private GoogleMap googleMap;
    private final HTML panel;
    private final MapOptions myOptions;
    private final List<Marker> markers = new ArrayList<Marker>();
    private final Map<BoatDto, Marker> boatMarkerMap = new HashMap<BoatDto, Marker>();
    private final Map<String, String> categoryMarkerImageMap = new HashMap<String, String>();
    private final PreloadedImage.OnLoadPreloadedImageHandler showImage = new PreloadedImage.OnLoadPreloadedImageHandler() {
        @Override
        public void onLoad(PreloadedImage image) {
            image.setWidth("32px");
        }
    };

    public MapWidget() {

        panel = new HTML();

        panel.setPixelSize(400, 400);
        panel.setVisible(true);
        myOptions = MapOptions.create();
        myOptions.setZoom(1);
        myOptions.setCenter(LatLng.create(48.383, -4.5));
        myOptions.setMapTypeId(MapTypeId.SATELLITE);

        googleMap = GoogleMap.create(panel.getElement(), myOptions);

        initWidget(panel);
    }

    private String createBoatInfos(BoatDto aBoat) {
        StringBuilder infos = new StringBuilder();


        // Création du tableau
        infos.append("<TABLE> <TR>");
        if (aBoat.getBoatImage().getUrl() != null) {
            PreloadedImage preloadedImage = new PreloadedImage(aBoat.getBoatImage().getUrl(), showImage);

            // Ajout de l'image du bateau
            infos.append("<TD><img src=\"")
                    .append(preloadedImage.getUrl())
                    .append("\" width=\"100\"><TD>");
        }

        // Ajout du nom du bateau
        infos.append("<TD><b><u>")
                .append(aBoat.getName())
                .append("</u></b><hr/>");
        infos.append(aBoat.getDescription())
                .append("<br/><br/>");

        // Ajout de la position du bateau
        infos.append("<b>Position :</b> (")
                .append(aBoat.getLatitude())
                .append(", ")
                .append(aBoat.getLongitude())
                .append(")<br/>");

        // Ajout de la category du bateau
        infos.append("<b>Category :</b> ")
                .append(aBoat.getCategory().getName())
                .append("</TD></TR>");

        return infos.toString();
    }

    public void attachInfoWindow(final Marker marker, BoatDto aBoat) {
        String infoContent = this.createBoatInfos(aBoat);
        final InfoWindow infoWindow = InfoWindow.create();
        infoWindow.setContent(infoContent);
        marker.addClickListener(new ClickHandler() {
            @Override
            public void handle(MouseEvent event) {
                infoWindow.open(googleMap, marker);
            }
        });
    }

    public void addBoats(List<BoatDto> boats) {

        googleMap = GoogleMap.create(panel.getElement(), myOptions);

        if (boats != null) {
            for (BoatDto boat : boats) {
                this.addBoat(boat);
            }
        }
    }

    public void setBoats(List<BoatDto> boats) {
        this.clear();
        this.addBoats(boats);
    }

    public void setBoat(BoatDto boat) {
        this.clear();
        this.addBoat(boat);
    }

    public void addBoat(BoatDto boat) {

        MarkerOptions newMarkerOpts = MarkerOptions
                .create();

        newMarkerOpts.setMap(googleMap);
        newMarkerOpts.setIcon(this.getMarkerUrl(boat));
        newMarkerOpts.setDraggable(false);
        newMarkerOpts.setAnimation(Animation.DROP);
        newMarkerOpts.setTitle(boat.getName());
        newMarkerOpts.setPosition(LatLng.create(
                boat.getLatitude(),
                boat.getLongitude()));

        Marker marker = Marker.create(newMarkerOpts);
        marker.setTitle(boat.getName());

        attachInfoWindow(marker, boat);

        boatMarkerMap.put(boat, marker);
        markers.add(marker);


    }

    public void removeMarker(Marker marker) {
        if (marker != null) {
            marker.setMap((GoogleMap) null);
            this.markers.remove(marker);
        }
    }

    public void removeBoat(BoatDto boat) {
        this.removeMarker(this.boatMarkerMap.get(boat));
        this.boatMarkerMap.remove(boat);
    }

    public void clear() {

        for (Marker marker : markers) {
            removeMarker(marker);
        }

        this.markers.clear();
        this.boatMarkerMap.clear();
    }

    private String getMarkerUrl(BoatDto aBoat) {
        //"images/markers/m1.png"
        String markerUrl = "images/markers/";

        // Récupération de l'image du marker pour cette catégorie
        String imageName = this.categoryMarkerImageMap.get(aBoat.getCategory().getName());

        // Si la category n'a pas encore d'image
        if (imageName == null || imageName.isEmpty()) {
            // S'il reste des images disponibles
            if (this.categoryMarkerImageMap.size() < 6) {
                // Récupération d'une nouvelle image
                imageName = "m" + this.categoryMarkerImageMap.size();
            } // Sinon, image par défaut
            else {
                imageName = "m";
            }

            // Enregistrement de l'image pour la catégory
            this.categoryMarkerImageMap.put(aBoat.getCategory().getName(), imageName);
        }



        return markerUrl + imageName + ".png";
    }
}